package com.ruowei.modules.foodOrder.web.rest;

import com.querydsl.core.group.GroupBy;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.ruowei.common.error.exception.CommonException;
import com.ruowei.modules.foodOrder.domain.*;
import com.ruowei.modules.foodOrder.repository.AttributeOptionsRepository;
import com.ruowei.modules.foodOrder.repository.MerchandiseAttributesRepository;
import com.ruowei.modules.foodOrder.repository.MerchandiseRepository;
import com.ruowei.modules.foodOrder.repository.MerchandiseSkuRepository;
import com.ruowei.modules.foodOrder.web.dto.AddAttributesDTO;
import com.ruowei.modules.foodOrder.web.dto.MerchandiseAttributeDTO;
import com.ruowei.modules.foodOrder.web.dto.OptionsDTO;
import com.ruowei.modules.foodOrder.web.dto.UpdateAttributesDTO;
import com.ruowei.modules.sys.repository.SysUserRepository;
import com.ruowei.modules.sys.utils.CommonUtils;
import com.ruowei.security.CurrentUser;
import com.ruowei.security.UserModel;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;

/**
 * REST controller for managing {@link MerchandiseAttributes}.
 */
@RestController
@RequestMapping("/api")
@Transactional
@Api(tags = "商品属性选项")
public class MerchandiseAttributesResource {

    private final Logger log = LoggerFactory.getLogger(MerchandiseAttributesResource.class);

    private final SysUserRepository sysUserRepository;
    private final MerchandiseRepository merchandiseRepository;
    private final MerchandiseAttributesRepository merchandiseAttributesRepository;
    private final AttributeOptionsRepository attributeOptionsRepository;
    private final MerchandiseSkuRepository merchandiseSkuRepository;
    private final JPAQueryFactory queryFactory;

    private final QMerchandiseAttributes qMerchandiseAttributes = QMerchandiseAttributes.merchandiseAttributes;
    private final QAttributeOptions qAttributeOptions = QAttributeOptions.attributeOptions;
    private final QMerchandiseSku qMerchandiseSku = QMerchandiseSku.merchandiseSku;
    private final QSkuOptionsRelationship qSkuOptionsRelationship = QSkuOptionsRelationship.skuOptionsRelationship;

    public MerchandiseAttributesResource(SysUserRepository sysUserRepository, MerchandiseRepository merchandiseRepository, MerchandiseAttributesRepository merchandiseAttributesRepository, AttributeOptionsRepository attributeOptionsRepository, MerchandiseSkuRepository merchandiseSkuRepository, JPAQueryFactory queryFactory) {
        this.sysUserRepository = sysUserRepository;
        this.merchandiseRepository = merchandiseRepository;
        this.merchandiseAttributesRepository = merchandiseAttributesRepository;
        this.attributeOptionsRepository = attributeOptionsRepository;
        this.merchandiseSkuRepository = merchandiseSkuRepository;
        this.queryFactory = queryFactory;
    }


    @PostMapping("/createAttributeOptions")
    @ApiOperation(value = "新增商品属性")
    public ResponseEntity<MerchandiseAttributes> createAttributeOptions(@RequestBody AddAttributesDTO dto,
                                                                        @ApiIgnore @CurrentUser UserModel userModel) {
        //删除默认属性
        queryFactory.update(qMerchandiseAttributes)
            .set(qMerchandiseAttributes.status, false)
            .where(qMerchandiseAttributes.merchandiseCode.eq(dto.getMerchandiseCode())
                .and(qMerchandiseAttributes.attributeName.eq("默认")))
            .execute();

        if (merchandiseAttributesRepository.existsByAttributeNameAndMerchandiseCodeAndStatus(dto.getName(), dto.getMerchandiseCode(), true)) {
            throw new CommonException("该商品已存在同名属性");
        }
        //新增属性
        MerchandiseAttributes merchandiseAttributes = new MerchandiseAttributes();
        String attributeCode = CommonUtils.getUUID();
        merchandiseAttributes.setMerchandiseCode(dto.getMerchandiseCode());
        merchandiseAttributes.setAttributeCode(attributeCode);
        merchandiseAttributes.setAttributeName(dto.getName());
        merchandiseAttributes.setStatus(true);
        merchandiseAttributes.setCreateTime(Instant.now());
        merchandiseAttributesRepository.save(merchandiseAttributes);
        //新增对应选项
        List<AttributeOptions> list = getAttributeOptions(new HashSet<>(dto.getList()), attributeCode);
        attributeOptionsRepository.saveAll(list);

        return ResponseEntity.ok(merchandiseAttributes);
    }


    @PostMapping("/updateAttributeOptions")
    @ApiOperation(value = "修改商品属性")
    public ResponseEntity<MerchandiseAttributes> updateAttributeOptions(@RequestBody UpdateAttributesDTO dto,
                                                                        @ApiIgnore @CurrentUser UserModel userModel) {
        Optional<MerchandiseAttributes> opt = merchandiseAttributesRepository.findOneByAttributeCodeAndStatus(dto.getAttributeCode(), true);
        if (!opt.isPresent()) {
            throw new CommonException("该属性不存在");
        }
        MerchandiseAttributes merchandiseAttributes = opt.get();
        Optional<Merchandise> merchandiseOpt = merchandiseRepository.findOneByMerchandiseCodeAndDeleteStatus(merchandiseAttributes.getMerchandiseCode(), false);
        if (!merchandiseOpt.isPresent()) {
            throw new CommonException("商品已删除");
        }
        if (merchandiseOpt.get().isPublishStatus()) {
            throw new CommonException("商品上架时无法修改商品属性");
        }
        merchandiseAttributes.setAttributeName(dto.getName());
        merchandiseAttributesRepository.save(merchandiseAttributes);
        //软删除对应的sku
        List<MerchandiseSku> skuList = queryFactory.select(qMerchandiseSku)
            .from(qMerchandiseAttributes)
            .innerJoin(qAttributeOptions).on(qMerchandiseAttributes.attributeCode.eq(qAttributeOptions.attributeCode))
            .innerJoin(qSkuOptionsRelationship).on(qSkuOptionsRelationship.optionCode.eq(qAttributeOptions.optionCode))
            .innerJoin(qMerchandiseSku).on(qMerchandiseSku.skuCode.eq(qSkuOptionsRelationship.skuCode))
            .where(qMerchandiseAttributes.attributeCode.eq(dto.getAttributeCode()))
            .fetch();
        if (!skuList.isEmpty()) {
            merchandiseSkuRepository.saveAll(skuList.stream().peek(merchandiseSku ->
                merchandiseSku.setStatus(false)).collect(Collectors.toList()));
        }

        List<MerchandiseSku> validSkus = queryFactory.selectFrom(qMerchandiseSku)
            .where(qMerchandiseSku.merchandiseCode.eq(merchandiseAttributes.getMerchandiseCode())
                .and(qMerchandiseSku.status.eq(true)))
            .fetch();
        if (validSkus.isEmpty()) {
            //如果没有sku了 则恢复默认sku
            recoveryDefaultAttribute(opt.get().getMerchandiseCode(), true);
        }
        //删除原有选项
        queryFactory.update(qAttributeOptions)
            .set(qAttributeOptions.status, false)
            .where(qAttributeOptions.attributeCode.eq(dto.getAttributeCode())
                .and(qAttributeOptions.optionName.ne("默认")))
            .execute();
        //新增选项
        List<AttributeOptions> list = getAttributeOptions(new HashSet<>(dto.getList()), dto.getAttributeCode());
        attributeOptionsRepository.saveAll(list);

        return ResponseEntity.ok(merchandiseAttributes);
    }

    private List<AttributeOptions> getAttributeOptions(Set<String> list2, String attributeCode) {
        queryFactory.update(qAttributeOptions)
            .set(qAttributeOptions.status, false)
            .where(qAttributeOptions.attributeCode.eq(attributeCode)
                .and(qAttributeOptions.optionName.eq("默认")))
            .execute();
        return list2.stream().map(s -> {
            AttributeOptions attributeOptions = new AttributeOptions();
            attributeOptions.setOptionCode(CommonUtils.getUUID());
            attributeOptions.setOptionName(s);
            attributeOptions.setAttributeCode(attributeCode);
            attributeOptions.setStatus(true);
            attributeOptions.setCreateTime(Instant.now());
            return attributeOptions;
        }).collect(Collectors.toList());
    }


    @PostMapping("/disableOptions")
    @ApiOperation(value = "停用/启用商品属性")
    @Deprecated
    public ResponseEntity<MerchandiseAttributes> disableOptions(@RequestBody OptionsDTO dto,
                                                                @ApiIgnore @CurrentUser UserModel userModel) {
        throw new CommonException("停用启用功能已废除");
    }


    @PostMapping("/deleteAttributeOptions")
    @ApiOperation(value = "删除商品属性")
    public ResponseEntity<Void> deleteAttributeOptions(@RequestParam String attributeCode,
                                                       @ApiIgnore @CurrentUser UserModel userModel) {
        Optional<MerchandiseAttributes> opt = merchandiseAttributesRepository.findOneByAttributeCode(attributeCode);
        if (!opt.isPresent()) {
            throw new CommonException("该属性不存在");
        }
        MerchandiseAttributes merchandiseAttributes = opt.get();
        long attributeCount = queryFactory.selectFrom(qMerchandiseAttributes)
            .where(qMerchandiseAttributes.merchandiseCode.eq(opt.get().getMerchandiseCode())
                .and(qMerchandiseAttributes.attributeCode.ne(attributeCode))
                .and(qMerchandiseAttributes.status.eq(true)))
            .fetchCount();

        //停用要判断有无在用的商品
        QMerchandise qMerchandise = QMerchandise.merchandise;
        long count = queryFactory.selectFrom(qMerchandise)
            .leftJoin(qMerchandiseAttributes).on(qMerchandise.merchandiseCode.eq(qMerchandiseAttributes.merchandiseCode))
            .where(qMerchandise.deleteStatus.eq(false)
                .and(qMerchandise.publishStatus.eq(true))
                .and(qMerchandiseAttributes.attributeCode.eq(attributeCode)))
            .fetchCount();
        if (count > 0) {
            throw new CommonException("该属性所属的商品在上架状态，请下架商品重试");
        }

        queryFactory.update(qMerchandiseAttributes)
            .set(qMerchandiseAttributes.status, false)
            .where(qMerchandiseAttributes.attributeCode.eq(attributeCode))
            .execute();
        queryFactory.update(qAttributeOptions)
            .set(qAttributeOptions.status, false)
            .where(qAttributeOptions.attributeCode.eq(attributeCode))
            .execute();
        //软删除对应的sku
        List<MerchandiseSku> skuList = queryFactory.select(qMerchandiseSku)
            .from(qMerchandiseAttributes)
            .innerJoin(qAttributeOptions).on(qMerchandiseAttributes.attributeCode.eq(qAttributeOptions.attributeCode))
            .innerJoin(qSkuOptionsRelationship).on(qSkuOptionsRelationship.optionCode.eq(qAttributeOptions.optionCode))
            .innerJoin(qMerchandiseSku).on(qMerchandiseSku.skuCode.eq(qSkuOptionsRelationship.skuCode))
            .where(qMerchandiseAttributes.attributeCode.eq(attributeCode))
            .fetch();
        if (!skuList.isEmpty()) {
            merchandiseSkuRepository.saveAll(skuList.stream().peek(merchandiseSku ->
                merchandiseSku.setStatus(false)).collect(Collectors.toList()));
        }

        List<MerchandiseSku> validSkus = queryFactory.selectFrom(qMerchandiseSku)
            .where(qMerchandiseSku.merchandiseCode.eq(merchandiseAttributes.getMerchandiseCode())
                .and(qMerchandiseSku.status.eq(true)))
            .fetch();

        if (attributeCount <= 0) {
            //此属性是最后一个属性，恢复默认属性
            recoveryDefaultAttribute(opt.get().getMerchandiseCode(), false);
        } else if (validSkus.isEmpty()) {
            //如果没有sku了 则恢复默认sku
            recoveryDefaultAttribute(opt.get().getMerchandiseCode(), true);
        }
        return ResponseEntity.ok().build();
    }

    private void recoveryDefaultAttribute(String merchandiseCode, Boolean skuOnly) {
        Optional<MerchandiseAttributes> attributesOptional =
            merchandiseAttributesRepository.findFirstByAttributeNameAndMerchandiseCode("默认", merchandiseCode);
        MerchandiseAttributes attributes;
        if (attributesOptional.isPresent()) {
            attributes = attributesOptional.get();
            if (!skuOnly) {
                attributes.setStatus(true);
                merchandiseAttributesRepository.saveAndFlush(attributes);
            }
        } else {
            attributes = new MerchandiseAttributes();
            attributes.setAttributeCode(CommonUtils.getUUID());
            attributes.setAttributeName("默认");
            attributes.setMerchandiseCode(merchandiseCode);
            attributes.setCreateTime(Instant.now());
            attributes.setStatus(true);
            merchandiseAttributesRepository.saveAndFlush(attributes);
        }

        Optional<AttributeOptions> optionsOptional =
            attributeOptionsRepository.findFirstByOptionNameAndAttributeCode("默认", attributes.getAttributeCode());
        AttributeOptions options;
        if (optionsOptional.isPresent()) {
            options = optionsOptional.get();
            if (!skuOnly) {
                options.setStatus(true);
                attributeOptionsRepository.saveAndFlush(options);
            }
        } else {
            options = new AttributeOptions();
            options.setAttributeCode(attributes.getAttributeCode());
            options.setCreateTime(Instant.now());
            options.setOptionCode(CommonUtils.getUUID());
            options.setOptionName("默认");
            options.setStatus(true);
            attributeOptionsRepository.saveAndFlush(options);
        }

        queryFactory.update(qMerchandiseSku)
            .set(qMerchandiseSku.status, false)
            .where(qMerchandiseSku.merchandiseCode.eq(merchandiseCode)
                .and(qMerchandiseSku.status.eq(true)))
            .execute();

        queryFactory.update(qMerchandiseSku)
            .set(qMerchandiseSku.status, true)
            .where(qMerchandiseSku.skuCode.eq(
                queryFactory.select(qSkuOptionsRelationship.skuCode)
                    .from(qSkuOptionsRelationship)
                    .leftJoin(qAttributeOptions).on(qAttributeOptions.optionCode.eq(qSkuOptionsRelationship.optionCode))
                    .leftJoin(qMerchandiseAttributes).on(qAttributeOptions.attributeCode.eq(qMerchandiseAttributes.attributeCode))
                    .where(qMerchandiseAttributes.attributeCode.eq(attributes.getAttributeCode()))
                    .where(qAttributeOptions.optionCode.eq(options.getOptionCode()))
                    .fetchFirst()
            )).execute();
    }

    @GetMapping("/getAttributeOptionsList")
    @ApiOperation(value = "获取商品属性列表")
    public ResponseEntity<List<MerchandiseAttributeDTO>> getAttributeOptionsList(@RequestParam String merchandiseCode,
                                                                                 @ApiIgnore @CurrentUser UserModel userModel) {
        List<MerchandiseAttributeDTO> result = new ArrayList<>(queryFactory.select(qMerchandiseAttributes, qAttributeOptions)
            .from(qMerchandiseAttributes)
            .leftJoin(qAttributeOptions).on(qMerchandiseAttributes.attributeCode.eq(qAttributeOptions.attributeCode))
            .where(qMerchandiseAttributes.merchandiseCode.eq(merchandiseCode)
                .and(qMerchandiseAttributes.status.eq(true))
                .and(qAttributeOptions.status.eq(true))
                .and(qMerchandiseAttributes.attributeName.ne("默认")))
            .orderBy(qMerchandiseAttributes.createTime.desc())
            .orderBy(qAttributeOptions.createTime.desc())
            .transform(GroupBy.groupBy(qMerchandiseAttributes).as(Projections.bean(MerchandiseAttributeDTO.class, qMerchandiseAttributes.attributeCode,
                qMerchandiseAttributes.attributeName, qMerchandiseAttributes.merchandiseCode, qMerchandiseAttributes.status, qMerchandiseAttributes.createTime,
                GroupBy.list(qAttributeOptions).as("optionalList"))))
            .values());

        return ResponseEntity.ok(result);
    }


    @GetMapping("/getAllAttributeOptionsList")
    @ApiOperation(value = "获取商品属性列表()")
    public ResponseEntity<List<MerchandiseAttributeDTO>> getAllAttributeOptionsList(@RequestParam String merchandiseCode,
                                                                                    @ApiIgnore @CurrentUser UserModel userModel) {
        List<MerchandiseAttributeDTO> result = new ArrayList<>(queryFactory.select(qMerchandiseAttributes, qAttributeOptions)
            .from(qMerchandiseAttributes)
            .leftJoin(qAttributeOptions).on(qMerchandiseAttributes.attributeCode.eq(qAttributeOptions.attributeCode))
            .where(qMerchandiseAttributes.merchandiseCode.eq(merchandiseCode)
                .and(qMerchandiseAttributes.status.eq(true))
                .and(qAttributeOptions.status.eq(true))
                .and(qMerchandiseAttributes.attributeName.ne("默认")))
            .orderBy(qMerchandiseAttributes.createTime.desc())
            .orderBy(qAttributeOptions.createTime.desc())
            .transform(GroupBy.groupBy(qMerchandiseAttributes).as(Projections.bean(MerchandiseAttributeDTO.class, qMerchandiseAttributes.attributeCode,
                qMerchandiseAttributes.attributeName, qMerchandiseAttributes.merchandiseCode, qMerchandiseAttributes.status, qMerchandiseAttributes.createTime,
                GroupBy.list(qAttributeOptions).as("optionalList"))))
            .values());

        return ResponseEntity.ok(result);
    }

    @GetMapping("/getOptionList")
    @ApiOperation(value = "获取属性选项列表")
    @Deprecated
    public ResponseEntity<List<AttributeOptions>> getOptionList(@RequestParam String attributeCode,
                                                                @ApiIgnore @CurrentUser UserModel userModel) {
        Optional<MerchandiseAttributes> opt = merchandiseAttributesRepository.findOneByAttributeCode(attributeCode);
        if (!opt.isPresent()) {
            throw new CommonException("该属性不存在");
        }
        List<AttributeOptions> result = attributeOptionsRepository.findAllByAttributeCodeAndStatus(attributeCode, true);

        return ResponseEntity.ok(result);
    }
}
